package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.DeviceCacheConstant;
import com.zzyl.dto.*;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.LocationTypeEnum;
import com.zzyl.enums.PhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliyunIotProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.DevicePropertyStatusVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import com.zzyl.vo.ThingModelPublishedVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private Client client;

    @Autowired
    private AliyunIotProperties iotProperties;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public DevicePropertyStatusVo queryDevicePropertyStatus(GivenDevicePhysicalModelDto dto) {
        DevicePropertyStatusVo devicePropertyStatusVo = new DevicePropertyStatusVo();
        QueryDevicePropertyStatusRequest request = new QueryDevicePropertyStatusRequest();
        request.setDeviceName(dto.getDeviceName());
        request.setIotInstanceId(iotProperties.getIotInstanceId());
//        request.setIotId(); IotId作为设备唯一标识符，和ProductKey与DeviceName组合是一一对应的关系。如果传入该参数，则无需传入ProductKey和DeviceName。如果您同时传入IotId和ProductKey与DeviceName组合，则以IotId为准。
        request.setProductKey(dto.getProductKey());
        try {
            QueryDevicePropertyStatusResponse response = client.queryDevicePropertyStatus(request);
            if (!response.getBody().success){
                log.error(response.getBody().getErrorMessage());
                throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
            }
            QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyDataList list = response.getBody().getData().getList();
            List<QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyDataListPropertyStatusInfo> propertyStatusInfo = list.getPropertyStatusInfo();
            devicePropertyStatusVo.setList(new DevicePropertyStatusVo.ListObject(propertyStatusInfo));
            return devicePropertyStatusVo;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
    }


    @Override
    public void deleteDevice(DeleteDeviceDto dto) {
        // 删除阿里云的
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        // 修改了前端 deviceName是前端传进来的
        request.setDeviceName(dto.getDeviceName());
        request.setIotId(dto.getIotId());
        request.setProductKey(dto.getProductKey());
        request.setIotInstanceId(iotProperties.getIotInstanceId());
        try {
            DeleteDeviceResponse response = client.deleteDevice(request);
            if (!response.getBody().success) {
                log.error(response.getBody().getErrorMessage());
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            log.error("阿里云删除设备失败");
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
        // 删除数据库的
        try {
            deviceMapper.deleteByIotId(dto.getIotId());
        } catch (Exception e) {
            log.error("数据库删除设备失败");
            log.error(e.getMessage(), e);
            throw new BaseException(BasicEnum.DATA_DELETE_ERROR);
        }
    }

    @Override
    public void updateDevice(UpdateDeviceDto dto) {
        // 修改阿里云IOT平台
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(iotProperties.getIotInstanceId());
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> deviceNickNameInfo
                = new ArrayList<>();
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo deviceNicknameInfo =
                new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        deviceNicknameInfo.setDeviceName(dto.getDeviceName());
        deviceNicknameInfo.setIotId(dto.getIotId());
        deviceNicknameInfo.setNickname(dto.getNickname());
        deviceNicknameInfo.setProductKey(dto.getProductKey());
        deviceNickNameInfo.add(deviceNicknameInfo);

        request.setDeviceNicknameInfo(deviceNickNameInfo);
        try {
            BatchUpdateDeviceNicknameResponse response = client.batchUpdateDeviceNickname(request);
            client.batchUpdateDeviceNickname(request);
            if (!response.getBody().success) {
                log.error("阿里云修改设备备注名称错误");
                log.error(response.getBody().getErrorMessage());
                throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            log.error("阿里云修改设备备注名称错误");
            log.error(e.getMessage(), e);
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        // 修改数据库
        Device device = BeanUtil.copyProperties(dto, Device.class);
        try {
            deviceMapper.updateByPrimaryKeySelective(device);
        } catch (Exception e) {
            log.error("数据库修改设备备注名称错误");
            throw new BaseException(BasicEnum.DATA_UPDATE_ERROR);
        }
    }

    @Override
    public ThingModelPublishedVo queryThingModelPublished(QueryThingModelPublishedDto dto) {
        ThingModelPublishedVo thingModelPublishedVo = new ThingModelPublishedVo();
        if (StringUtils.isEmpty(dto.getProductKey())) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        QueryThingModelPublishedRequest request = new QueryThingModelPublishedRequest();
        request.setProductKey(dto.getProductKey());
        request.setIotInstanceId(iotProperties.getIotInstanceId());
        try {
            QueryThingModelPublishedResponse response = client.queryThingModelPublished(request);
            if (response.getBody().success) {
                String thingModelJson = response.getBody().getData().getThingModelJson();
                thingModelPublishedVo.setThingModelJson(thingModelJson);
                return thingModelPublishedVo;
            } else {
                log.error(response.getBody().getErrorMessage());
                throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
    }
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailDto dto) {
        DeviceVo result = new DeviceVo();
        // 查询mysql
        Device device = deviceMapper.selectByIotId(dto.getIotId());
        if (device == null) {
            throw new BaseException(BasicEnum.DATA_NOT_EXIST);
        }
        BeanUtil.copyProperties(device, result);
        // 查询阿里云
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.setDeviceName(device.getDeviceName());
        request.setIotInstanceId(iotProperties.getIotInstanceId());
        request.setIotId(dto.getIotId());
        request.setProductKey(device.getProductKey());
        try {
            QueryDeviceDetailResponse response = client.queryDeviceDetail(request);
            if (response.getBody().success) {
                QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.getBody().getData();
                BeanUtil.copyProperties(data, result, CopyOptions.create().ignoreNullValue());
            } else {
                log.error("查询设备详情异常：{}", response.getBody().getErrorMessage());
                throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        // 合并
        return result;
    }


    @Override
    public PageResponse<DeviceVo> pageQuery(DevicePageQueryDto dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        Page<DeviceVo> page = deviceMapper.pageQuery(dto);
        return PageResponse.of(page, DeviceVo.class);
    }


    @Override
    public void registerDevice(DeviceDto dto) {
        // 判断重名
        Device deviceDB = deviceMapper.selectByName(dto.getDeviceName());
        if (deviceDB != null) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        // 保存到阿里云
        RegisterDeviceResponse response = null;
        RegisterDeviceRequest request = dto.getRegisterDeviceRequest();
        request.setIotInstanceId(iotProperties.getIotInstanceId());
        try {
            response = client.registerDevice(request);
            if (!response.getBody().success) {
                log.error("注册设备失败：{}", response.getBody().getErrorMessage());
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        // 保存到mysql
        String iotId = response.getBody().getData().getIotId();
        Device device = BeanUtil.copyProperties(dto, Device.class);
        device.setIotId(iotId);
        if (LocationTypeEnum.PORTABLE_DEVICE.getValue() == dto.getLocationType()) {
            device.setPhysicalLocationType(PhysicalLocationTypeEnum.ELDER.getValue());
        }
        try {
            deviceMapper.insertSelective(device);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            // 把设备从阿里云再删除
            DeleteDeviceRequest deleteRequest = new DeleteDeviceRequest();
            deleteRequest.setIotInstanceId(iotProperties.getIotInstanceId());
            deleteRequest.setProductKey(dto.getProductKey());
            deleteRequest.setDeviceName(dto.getDeviceName());
            deleteRequest.setIotId(iotId);
            try {
                DeleteDeviceResponse deleteResponse = client.deleteDevice(deleteRequest);
                if (!deleteResponse.getBody().success) {
                    log.error("删除设备失败：{}", response.getBody().getErrorMessage());
                    throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
                }
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        }
    }

    @Override
    public List<ProductVo> allProduct() {
        String json = redisTemplate.opsForValue().get(DeviceCacheConstant.PRODUCT_LIST);
        if (StringUtils.isEmpty(json)) {
            return new ArrayList<>();
        }
        return JSONUtil.toList(json, ProductVo.class);
    }

    @Override
    public void syncProductList() {
        // 向阿里云发查询产品列表请求
        QueryProductListRequest request = new QueryProductListRequest();
        request.setIotInstanceId(iotProperties.getIotInstanceId());
        request.setPageSize(10);
        request.setCurrentPage(1);
        try {
            QueryProductListResponse response = client.queryProductList(request);
            // 判断是否成功
            if (response.getBody().success) {
                // 解析响应结果
                List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfo = response.getBody().getData().getList().getProductInfo();
                // 保存到redis
                redisTemplate.opsForValue().set(DeviceCacheConstant.PRODUCT_LIST, JSONUtil.toJsonStr(productInfo));
            } else {
                throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
    }
    @Override
    public Device queryByIotId(String iotId) {
        return deviceMapper.selectByIotId(iotId);
    }
}